home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
United Public Domain Gold 4
/
United Public Domain Gold 4.iso
/
fredfish
/
ff.0065.dms
/
ff.0065.adf
/
Bawk
/
bawkdo.c
< prev
next >
Wrap
C/C++ Source or Header
|
1987-04-04
|
12KB
|
768 lines
/*
* Bawk C actions interpreter
*/
#include <stdio.h>
#include "bawk.h"
dopattern( pat )
char *pat;
{
Where = PATTERN;
Actptr = pat;
getoken();
expression();
return popint();
}
doaction( act )
char *act;
{
Where = ACTION;
Actptr = act;
getoken();
while ( Token!=T_EOF )
statement();
}
expression()
{
expr1();
if ( Token==T_ASSIGN )
{
getoken();
assignment( expression() );
}
}
expr1()
{
int ival;
expr2();
for ( ;; )
{
if ( Token==T_LIOR )
{
getoken();
ival = popint();
expr2();
pushint( popint() || ival );
}
else
return;
}
}
expr2()
{
int ival;
expr3();
for ( ;; )
{
if ( Token==T_LAND )
{
getoken();
ival = popint();
expr3();
pushint( popint() && ival );
}
else
return;
}
}
expr3()
{
int ival;
expr4();
for ( ;; )
{
if ( Token==T_IOR )
{
getoken();
ival = popint();
expr4();
pushint( popint() | ival );
}
else
return;
}
}
expr4()
{
int ival;
expr5();
for ( ;; )
{
if ( Token==T_AND )
{
getoken();
ival = popint();
expr5();
pushint( popint() & ival );
}
else
return;
}
}
expr5()
{
int ival;
expr6();
for ( ;; )
{
if ( Token==T_XOR )
{
getoken();
ival = popint();
expr6();
pushint( popint() ^ ival );
}
else
return;
}
}
expr6()
{
int ival;
expr7();
for ( ;; )
{
if ( Token==T_EQ )
{
getoken();
ival = popint();
expr7();
pushint( ival == popint() );
}
else if ( Token==T_NE )
{
getoken();
ival = popint();
expr7();
pushint( ival != popint() );
}
else
return;
}
}
expr7()
{
int ival;
expr8();
for ( ;; )
{
if ( Token==T_LE )
{
getoken();
ival = popint();
expr8();
pushint( ival <= popint() );
}
else if ( Token==T_GE )
{
getoken();
ival = popint();
expr8();
pushint( ival >= popint() );
}
else if ( Token==T_LT )
{
getoken();
ival = popint();
expr8();
pushint( ival < popint() );
}
else if ( Token==T_GT )
{
getoken();
ival = popint();
expr8();
pushint( ival > popint() );
}
else
return;
}
}
expr8()
{
int ival;
expr9();
for ( ;; )
{
if ( Token==T_SHL )
{
getoken();
ival = popint();
expr9();
pushint( ival << popint() );
}
else if ( Token==T_SHR )
{
getoken();
ival = popint();
expr9();
pushint( ival >> popint() );
}
else
return;
}
}
expr9()
{
int ival;
expr10();
for ( ;; )
{
if ( Token==T_ADD )
{
getoken();
ival = popint();
expr10();
pushint( ival + popint() );
}
else if ( Token==T_SUB )
{
getoken();
ival = popint();
expr10();
pushint( ival - popint() );
}
else
return;
}
}
expr10()
{
int ival;
primary();
for ( ;; )
{
if ( Token==T_MUL )
{
getoken();
ival = popint();
primary();
pushint( ival * popint() );
}
else if ( Token==T_DIV )
{
getoken();
ival = popint();
primary();
pushint( ival / popint() );
}
else if ( Token==T_MOD )
{
getoken();
ival = popint();
primary();
pushint( ival % popint() );
}
else
return;
}
}
primary()
{
int index;
DATUM data;
VARIABLE *pvar;
switch ( Token )
{
case T_LPAREN:
/*
* it's a parenthesized expression
*/
getoken();
expression();
if ( Token!=T_RPAREN )
error( "missing ')'", ACT_ERROR );
getoken();
break;
case T_LNOT:
getoken();
primary();
pushint( ! popint() );
break;
case T_NOT:
getoken();
primary();
pushint( ~ popint() );
break;
case T_ADD:
getoken();
primary();
break;
case T_SUB:
getoken();
primary();
pushint( - popint() );
break;
case T_INCR:
case T_DECR:
preincdec();
break;
case T_MUL:
getoken();
primary();
/*
* If item on stack is an LVALUE, do an extra level of
* indirection before changing it to an LVALUE.
*/
if ( Stackptr->lvalue )
Stackptr->value.ptrptr = *Stackptr->value.ptrptr;
Stackptr->lvalue = 1;
--Stackptr->class;
break;
case T_AND:
getoken();
primary();
if ( Stackptr->lvalue )
Stackptr->lvalue = 0;
else
error( "'&' operator needs an lvalue", ACT_ERROR );
break;
case T_CONSTANT:
pushint( Value.ival );
getoken();
break;
case T_REGEXP:
/*
* It's a regular expression - parse it and compile it.
*/
if ( Where == PATTERN )
{
/*
* We're processing a pattern right now - perform a
* match of the regular expression agains input line.
*/
unparse( Fields, Fieldcount, Linebuf, Fieldsep );
pushint( match( Linebuf, Value.dptr ) );
}
else
push( 1, ACTUAL, BYTE, &Value );
getoken();
break;
case T_NF:
pushint( Fieldcount );
getoken();
break;
case T_NR:
pushint( Recordcount );
getoken();
break;
case T_FS:
Fieldsep[1] = 0;
data.dptr = Fieldsep;
push( 0, LVALUE, BYTE, &data );
getoken();
break;
case T_RS:
Recordsep[1] = 0;
data.dptr = Recordsep;
push( 0, LVALUE, BYTE, &data );
getoken();
break;
case T_FILENAME:
data.dptr = Filename;
push( 1, ACTUAL, BYTE, &data );
getoken();
break;
case T_DOLLAR:
/*
* It's a reference to one (or all) of the words in Linebuf.
*/
getoken();
primary();
if ( index = popint() )
{
if ( index > Fieldcount )
index = Fieldcount;
else if ( index < 1 )
index = 1;
data.dptr = Fields[ index-1 ];
}
else
{
/*
* Reconstitute the line buffer in case any of the
* fields have been changed.
*/
unparse( Fields, Fieldcount, Linebuf, Fieldsep );
data.dptr = Linebuf;
}
/*
* $<expr>'s are treated the same as string constants:
*/
push( 1, ACTUAL, BYTE, &data );
break;
case T_STRING:
push( 1, ACTUAL, BYTE, &Value );
getoken();
break;
case T_FUNCTION:
/*
* Do a built-in function call
*/
index = Value.ival;
getoken();
function( index );
break;
case T_VARIABLE:
pvar = Value.dptr;
getoken();
/*
* it's a plain variable. The way a variable is
* represented on the stack depends on its type:
* lvalue class value.dptr
* vars: 1 0 address of var
* ptrs: 1 1 ptr to address of ptr
* array: 0 1 address of var
*/
if ( pvar->vclass && !pvar->vlen )
/* it's a pointer */
data.dptr = &pvar->vptr;
else
/* an array or simple variable */
data.dptr = pvar->vptr;
/*
* If it's an array it can't be used as an LVALUE.
*/
push( pvar->vclass, !pvar->vlen, pvar->vsize, &data );
break;
case T_EOF:
break;
default:
syntaxerror();
}
/*
* a "[" means it's an array reference
*/
if ( Token==T_LBRACKET )
{
getoken();
if ( ! Stackptr->class )
error( "'[]' needs an array or pointer", ACT_ERROR );
/*
* compute the subscript
*/
expression();
if ( Token!=T_RBRACKET )
error( "missing ']'", ACT_ERROR );
getoken();
index = popint();
/*
* compute the offset (subscript times two for int arrays)
* and then the effective address.
*/
index *= Stackptr->size;
if ( Stackptr->lvalue )
/*
* It's a pointer - don't forget that the stack top
* item's value is the address of the pointer so we
* must do another level of indirection.
*/
Stackptr->value.dptr = *Stackptr->value.ptrptr+index;
else
/*
* It's a plain array - the stack top item's value is
* the address of the first element in the array.
*/
Stackptr->value.dptr += index;
/*
* The stack top item now becomes an LVALUE, but we've
* reduced the indirection level.
*/
Stackptr->lvalue = 1;
--Stackptr->class;
}
if ( Token==T_INCR || Token==T_DECR )
postincdec();
}
preincdec()
{
/*
* Pre increment/decrement
*/
int incr;
incr = Token==T_INCR ? 1 : -1;
getoken();
primary();
if ( Stackptr->lvalue )
{
if ( Stackptr->class )
incr *= Stackptr->size;
*Stackptr->value.ptrptr += incr;
}
else
error( "pre '++' or '--' needs an lvalue", ACT_ERROR );
}
postincdec()
{
/*
* Post increment/decrement
*/
char **pp;
int incr;
incr = Token==T_INCR ? 1 : -1;
getoken();
if ( Stackptr->lvalue )
{
if ( Stackptr->class )
{
/*
* It's a pointer - save its old value then
* increment/decrement the pointer. This makes the
* item on top of the stack look like an array, which
* means it can no longer be used as an LVALUE. This
* doesn't really hurt, since it doesn't make much
* sense to say:
* char *cp;
* cp++ = value;
*/
pp = *Stackptr->value.ptrptr;
*Stackptr->value.ptrptr += incr * Stackptr->size;
Stackptr->value.ptrptr = pp;
}
else
{
/*
* It's a simple variable - save its old value then
* increment/decrement the variable. This makes the
* item on top of the stack look like a constant,
* which means it can no longer be used as an LVALUE.
* Same reasoning as above.
*/
if ( Stackptr->size == BYTE )
pp = *Stackptr->value.dptr;
else
pp = *Stackptr->value.ptrptr;
*Stackptr->value.ptrptr += incr;
Stackptr->value.ival = pp;
}
Stackptr->lvalue = 0;
}
else
error( "post '++' or '--' needs an lvalue", ACT_ERROR );
}
statement()
{
/*
* Evaluate a statement
*/
char *repeat, *body;
switch ( Token )
{
case T_EOF:
break;
case T_CHAR:
case T_INT:
declist();
break;
case T_LBRACE:
/*
* parse a compound statement
*/
getoken();
while ( !Saw_break && Token!=T_RBRACE )
statement();
if ( Token==T_RBRACE )
getoken();
break;
case T_IF:
/*
* parse an "if-else" statement
*/
if ( getoken() != T_LPAREN )
syntaxerror();
getoken();
expression();
if ( Token!=T_RPAREN )
syntaxerror();
getoken();
if ( popint() )
{
statement();
if ( Token==T_ELSE )
{
getoken();
skipstatement();
}
}
else
{
skipstatement();
if ( Token==T_ELSE )
{
getoken();
statement();
}
}
break;
case T_WHILE:
/*
* parse a "while" statement
*/
repeat = Actptr;
for ( ;; )
{
if ( getoken() != T_LPAREN )
syntaxerror();
getoken();
expression();
if ( Token!=T_RPAREN )
syntaxerror();
if ( popint() )
{
body = Actptr;
getoken();
statement();
if ( Saw_break )
{
Actptr = body;
Saw_break = 0;
break;
}
Actptr = repeat;
}
else
break;
}
getoken();
skipstatement();
break;
case T_BREAK:
/*
* parse a "break" statement
*/
getoken();
Saw_break = 1;
break;
case T_SEMICOLON:
break;
default:
expression();
popint();
}
if ( Token==T_SEMICOLON )
getoken();
}
skipstatement()
{
/*
* Skip a statement
*/
switch ( Token )
{
case T_LBRACE:
/*
* skip a compound statement
*/
skip( T_LBRACE, T_RBRACE );
break;
case T_IF:
/*
* skip an "if-else" statement
*/
getoken(); /* skip 'if' */
skip( T_LPAREN, T_RPAREN );
skipstatement();
if ( Token==T_ELSE )
{
getoken(); /* skip 'else' */
skipstatement();
}
break;
case T_WHILE:
/*
* skip a "while" statement
*/
getoken(); /* skip 'while' */
skip( T_LPAREN, T_RPAREN );
skipstatement();
break;
default:
/*
* skip a one-liner
*/
while (Token!=T_SEMICOLON && Token!=T_RBRACE && Token!=T_EOF)
getoken();
if ( Token==T_EOF )
error( "unexpected end", ACT_ERROR );
if ( Token==T_SEMICOLON )
getoken();
}
}
skip( left, right )
char left, right;
{
/*
* Skip matched left and right delimiters and everything in between
*/
int parity;
char *save, errmsg[ 80 ];
parity = 1;
save = Actptr;
while ( getoken() != T_EOF )
{
if ( Token == left )
{
save = Actptr;
++parity;
}
else if ( Token == right )
--parity;
if ( !parity )
{
getoken();
return;
}
}
Actptr = save;
sprintf( errmsg, "mismatched '%c' and '%c'", left, right );
error( errmsg, ACT_ERROR );
}
syntaxerror()
{
error( "syntax error", ACT_ERROR );
}